package http

import (
	"context"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
	"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/certificates"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"go.uber.org/zap"
	"mall-portalv2/conf"
	"mall-portalv2/global"
	"mall-portalv2/internal/model"
	"mall-portalv2/internal/server/ctx"
	"net/http"
	"time"
)

func CallBackAliPayHandlerFunc(c *gin.Context) {
	app := ctx.Gin{C: c}

	//responseData := alipay.TradeNotification{}

	for k, v := range c.Request.Form {
		global.Log.Info("key, value", zap.Any("key", k), zap.Any("value", v))
	}

	notify_time := c.PostForm("notify_time")
	notify_type := c.PostForm("notify_type")
	notify_id := c.PostForm("notify_id")
	sign_type := c.PostForm("sign_type")
	sign := c.PostForm("sign")
	trade_no := c.PostForm("trade_no")
	app_id := c.PostForm("app_id")
	auth_app_id := c.PostForm("auth_app_id")
	out_trade_no := c.PostForm("out_trade_no")
	trade_status := c.PostForm("trade_status")
	total_amount := c.PostForm("total_amount")
	receipt_amount := c.PostForm("receipt_amount")

	temp := gin.H{
		"notify_time":    notify_time,
		"notify_type":    notify_type,
		"notify_id":      notify_id,
		"sign_type":      sign_type,
		"sign":           sign,
		"trade_no":       trade_no,
		"app_id":         app_id,
		"auth_app_id":    auth_app_id,
		"out_trade_no":   out_trade_no,
		"trade_status":   trade_status,
		"total_amount":   total_amount,
		"receipt_amount": receipt_amount,
	}

	global.Log.Info("回调接口映射完成", zap.Any("data", temp))

	nowTime := time.Now()

	if trade_status == "TRADE_SUCCESS" {
		// TODO: 交易完成
		// TODO: 先查询一下 订单状态
		orderResult, err := svc.QueryOmsOrderWhereOrderSn(c, out_trade_no)
		if err != nil {
			global.Log.Error("退款时，查询订单错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		// 订单状态：0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单
		if orderResult.Status != 0 {
			global.Log.Info("不是待付款的订单，没必要修改成待发货", zap.Any("orderResult", orderResult))
			app.Response(http.StatusOK, ctx.StatusOK, nil)
			return
		}

		updates := make(map[string]interface{})
		jsontemp, _ := json.Marshal(temp)
		updates["pay_type"] = 1
		updates["status"] = 1
		updates["payment_time"] = &nowTime
		updates["modify_time"] = &nowTime
		updates["payment_data"] = string(jsontemp)
		if err := svc.UpdateOrderWhereOrderSn(c, out_trade_no, updates); err != nil {
			global.Log.Error("更新订单信息失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		// TODO: 减少商品数量

		if err := updateProductWhereOrderSn(out_trade_no); err != nil {
			global.Log.Error("更新库存失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		global.Log.Info("交易完成,库存更新成功", zap.Any("updates", updates))
	}

	app.Response(http.StatusOK, ctx.OK, temp)
}

func CallBackWechatPayHandlerFunc(c *gin.Context) {
	app := ctx.Gin{C: c}

	//responseData := notify.Request{}
	//if err := common.BindAndCheck(c, &responseData); err != nil {
	//	global.Log.Error("请求参数不正确", zap.Error(err))
	//	app.Response(http.StatusBadRequest, ctx.StatusBadRequest, err)
	//	return
	//}
	//
	//global.Log.Info("微信支付回调映射完成", zap.Any("data", responseData))

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(conf.Config.WechatPay.PrivateKeyPath)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
		return
	}

	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(conf.Config.WechatPay.MchID, conf.Config.WechatPay.MchCertificateSerialNumber, mchPrivateKey, conf.Config.WechatPay.MchAPIv3Key),
	}

	contextWx := context.Background()

	client, err := core.NewClient(contextWx, opts...)
	if err != nil {
		global.Log.Error("请求参数不正确", zap.Error(err))
		app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
		return
	}

	//wechatSvc := app2.AppApiService{Client: client}
	wechatSvc := certificates.CertificatesApiService{Client: client}
	resp, result, err := wechatSvc.DownloadCertificates(context.Background())

	global.Log.Info("证书下载完毕", zap.Any("result.Response.StatusCode", result.Response.StatusCode), zap.Any("resp", resp.Data))

	certVisitor := downloader.MgrInstance().GetCertificateVisitor(conf.Config.WechatPay.MchID)

	handler, err := notify.NewRSANotifyHandler(
		conf.Config.WechatPay.MchAPIv3Key,
		verifiers.NewSHA256WithRSAVerifier(certVisitor),
	)

	type contentType struct {
		Mchid           *string    `json:"mchid"`
		Appid           *string    `json:"appid"`
		CreateTime      *time.Time `json:"create_time"`
		OutContractCode *string    `json:"out_contract_code"`
	}

	content := new(contentType)

	notifyReq, err := handler.ParseNotifyRequest(context.Background(), c.Request, content)
	//transaction := new(payments.Transaction)

	global.Log.Info("回调解析完毕", zap.Any("notifyReq", notifyReq))

	data := wechatData{}
	json.Unmarshal([]byte(notifyReq.Resource.Plaintext), &data)
	nowTime := time.Now()
	if data.TradeState == "SUCCESS" {

		// TODO: 先根据交易流水号查到订单编号
		result, err := svc.QueryPayLogsWherePaySnNoWay(c, data.OutTradeNo)
		if err != nil {
			global.Log.Error("查询支付流水号失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		// TODO: 先查询一下 订单状态
		orderResult, err := svc.QueryOmsOrderWhereOrderSn(c, result.OrderSn)
		if err != nil {
			global.Log.Error("退款时，查询订单错误", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		// 订单状态：0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单
		if orderResult.Status != 0 {
			global.Log.Info("不是待付款的订单，没必要修改成待发货", zap.Any("orderResult", orderResult))
			app.Response(http.StatusOK, ctx.StatusOK, nil)
			return
		}

		// TODO: 交易完成
		//UpdateOrder
		updates := make(map[string]interface{})
		updates["pay_type"] = 2
		updates["status"] = 1
		updates["payment_time"] = &nowTime
		updates["modify_time"] = &nowTime
		updates["payment_data"] = notifyReq.Resource.Plaintext
		if err := svc.UpdateOrderWhereOrderSn(c, result.OrderSn, updates); err != nil {
			global.Log.Error("更新订单信息失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		// TODO: 减少商品数量
		if err := updateProductWhereOrderSn(result.OrderSn); err != nil {
			global.Log.Error("更新库存失败", zap.Error(err))
			app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, nil)
			return
		}

		global.Log.Info("交易完成,库存更新成功", zap.Any("updates", updates))

	} else {
		global.Log.Info("支付失败")
	}

	app.Response(http.StatusOK, ctx.OK, nil)
}

func CallBackTempHandlerFunc(c *gin.Context) {
	app := ctx.Gin{C: c}

	str := `{
    "AliPay": "",
    "id": 10,
    "returnSn": "61923601088158624087420927",
    "orderId": 89,
    "orderItemId": 1,
    "companyAddressId": 0,
    "productId": 1,
    "orderSn": "230322213218479684194304",
    "createTime": "Mar 22, 2023 9:53:53 AM",
    "memberId": 6192360,
    "memberUsername": "13331909118",
    "returnAmount": 30,
    "returnName": "黄华",
    "returnPhone": "13331909118",
    "returnType": 1,
    "status": 0,
    "handleTime": "Mar 22, 2023 9:54:13 AM",
    "productPic": "https://cdn.iotdreamcatcher.net.cn/mall/images/20230320/796199d0-9f53-4bbf-ba3e-62585305155a.jpeg",
    "productName": "原创设计?家超智能陪伴灯",
    "productBrand": "原创设计?家超智能陪伴灯",
    "productAttr": "[{\"key\":\"颜色\",\"value\":\"baby蓝\"}]",
    "productCount": 1,
    "productPrice": 689,
    "productRealPrice": 459,
    "reason": "不想要了",
    "description": "帮忙退下款",
    "proofPics": "",
    "handleMan": "Lyt",
    "receiptStatus": 1
}`

	sendData := model.TradeRefundData{}

	json.Unmarshal([]byte(str), &sendData)

	Refundupdates := make(map[string]interface{})
	Refundupdates["status"] = 2

	Orderupdates := make(map[string]interface{})
	Orderupdates["status"] = 4

	price := 30.00

	result, err := svc.QueryOmsOrderWhereId(c, sendData.OrderId, sendData.MemberId)
	if err != nil {
		global.Log.Error("查询失败", zap.Error(err))
		app.Response(http.StatusInternalServerError, ctx.StatusInternalServerError, err)
		return
	}

	global.Log.Info("打印订单详情接口", zap.Any("result", result))

	//	TODO: 微信退款
	if err := svc.WechatTradeRefund(c, result, sendData, price); err != nil {
		global.Log.Error("订单退款失败, 更新状态到1", zap.Error(err))
		if sendData.ReturnType == 1 {
			Refundupdates["status"] = 0
		} else {
			Refundupdates["status"] = 1
		}
		if err := svc.UpdateOmsOrderReturnApply(c, sendData.Id, Refundupdates); err != nil {
			global.Log.Error("订单退款失败", zap.Error(err))
			return
		}
	}
	global.Log.Info("微信退款完成")
	if err := svc.UpdateOmsOrderReturnApplyAndOrder(sendData.Id, result.ID, Refundupdates, Orderupdates); err != nil {
		global.Log.Error("退款成功，订单和退款单同步失败", zap.Error(err))
		return
	}
	// TODO: 释放锁住的库存
	if err := svc.UnLockOmsOrder(c, result.ID); err != nil {
		global.Log.Error("mysql err", zap.Error(err))
		return
	}
	global.Log.Info("恢复锁掉的库存", zap.Any("result", result))
	// TODO: 失效掉对应的订单记录
	CrowdFundingLogUpdates := make(map[string]interface{})
	CrowdFundingLogUpdates["status"] = 0
	if err := svc.UpdateCrowdFundingLogWhereMemberIdAndOrdId(c, result.ID, result.MemberId, CrowdFundingLogUpdates); err != nil {
		global.Log.Error("mysql err", zap.Error(err))
		return
	}
	global.Log.Info("恢复对应的众筹购买记录", zap.Any("result", result))

	app.Response(http.StatusOK, ctx.OK, nil)
}

func updateProductWhereOrderSn(OrderSn string) error {
	ctx := context.Background()
	//	根据订单找到对应的产品信息
	orderResult, err := svc.QueryOmsOrderWhereOrderSn(ctx, OrderSn)
	if err != nil {
		global.Log.Error("同步库存失败", zap.Error(err))
		return err
	}

	orderItemResult, err := svc.QueryOmsOrderItemWhereOrderId(ctx, orderResult.ID)
	if err != nil {
		global.Log.Error("同步库存失败", zap.Error(err))
		return err
	}
	for _, item := range orderItemResult {
		// TODO: 修改对应的商品的库存
		global.Log.Info("修改库存", zap.Any("众筹ID", item.PromotionId), zap.Any("众筹SkuID", item.PromotionSkuId))

		if err := svc.UpdateProductAndCrowdFunding(ctx, item.ProductId, item.ProductSkuId, item.PromotionId, item.PromotionSkuId, item.OrderId, orderResult.MemberId); err != nil {
			global.Log.Error("mysql err", zap.Error(err))
			continue
		}
	}

	return nil
}

type wechatData struct {
	Mchid          string    `json:"mchid"`
	Appid          string    `json:"appid"`
	OutTradeNo     string    `json:"out_trade_no"`
	TransactionId  string    `json:"transaction_id"`
	TradeType      string    `json:"trade_type"`
	TradeState     string    `json:"trade_state"`
	TradeStateDesc string    `json:"trade_state_desc"`
	BankType       string    `json:"bank_type"`
	Attach         string    `json:"attach"`
	SuccessTime    time.Time `json:"success_time"`
	Payer          struct {
		Openid string `json:"openid"`
	} `json:"payer"`
	Amount struct {
		Total         int    `json:"total"`
		PayerTotal    int    `json:"payer_total"`
		Currency      string `json:"currency"`
		PayerCurrency string `json:"payer_currency"`
	} `json:"amount"`
}
